home *** CD-ROM | disk | FTP | other *** search
/ Magnum One / Magnum One (Mid-American Digital) (Disc Manufacturing).iso / d12 / asmbler.arc / PAINT.ASM < prev    next >
Assembly Source File  |  1988-11-19  |  20KB  |  589 lines

  1.         page    60,132
  2.         title   PAINT
  3.  
  4. public  paint
  5.  
  6. ; Routine to fill an area
  7. ; Ref: Christopher Morgan, Bluebook of Assembly Routines for the
  8. ; IBM PC & XT, Plume/Waite (1984), pp. 156-160
  9. ;
  10. ; Callable from Pascal as
  11. ;
  12. ; PROCEDURE PAINT (x,y,color : integer);
  13. ;
  14. ; This routine fills  an area on  the graphics screen  with a  specified
  15. ; color.  It starts "painting" at a specified interior position  filling
  16. ; a region bounded by a "boundary" color.
  17. ;
  18. ; The region must be  completely surrounded by a  boundary drawn in  the
  19. ; boundary color.   Any  paint color  in  the region  can  obstruct  the
  20. ; filling process, acting just like a boundary.  This algorithm uses its
  21. ; own stack.  If the  region is too complex,  this stack will  overflow.
  22. ; There is no check for such a stack overflow, but a check can easily be
  23. ; added.
  24. ;
  25. ; Upon entry:
  26. ;
  27. ;       x-coordinate of interior point is in SI
  28. ;       y-coordinate of interior point is in DI
  29. ;       paint color is in low byte of global variable "color"
  30. ;       boundary color is in high byte of global variable "color"
  31. ;       ES points to video RAM (IBM color display at B800h)
  32. ;       DS points to data segment of SETPT and LOCATE routines
  33. ;
  34. ;       Coordinate  system  origin  is  at  top  left  corner,  with   y
  35. ;       increasing downward.
  36. ;
  37. ; Output:
  38. ;       just to screen
  39. ;
  40. ; Registers modified:
  41. ;       none
  42. ;
  43. ; Preliminary push and pop procedures
  44. ;
  45. ; pushpaint pushes x- and y- coordinates on paint stack
  46.  
  47. ;=======================================================================
  48. ; Quadscreen monochrome video buffer stores  bits in each scanline  from
  49. ; 0..1023 in  128 consecutive  bytes,although only  0..967 are  visible.
  50. ; Successive scan lines  are in  consecutive groups of  128 bytes,  with
  51. ; scan lines 0..511 filling exactly 64K bytes.  A second 64K byte  image
  52. ; immediately follows, but for the moment, we ignore it and assume  that
  53. ; it is not selected.
  54.  
  55. quadscreen SEGMENT AT 0C000h
  56.         dw      20000 dup (?)
  57. quadscreen ENDS
  58.  
  59. ;=======================================================================
  60.  
  61. stacksize equ   2048d
  62.  
  63. paintstack SEGMENT
  64.         dw      stacksize dup (?)
  65. paintstack ENDS
  66.  
  67. ;=======================================================================
  68.  
  69. $paint  SEGMENT PARA PUBLIC 'CODE'
  70.  
  71. scr_top equ     0d              ; top screen line
  72. scr_bot equ     511d            ; bottom screen line
  73. scr_right equ   1023d           ; right screen column (only 0..967 displayable)
  74. scr_left  equ   0d              ; left screen column
  75. y_inc   equ     (scr_right+1)/8 ; bytes/scanline
  76.  
  77. ; local constants
  78.  
  79. bmask   db      80h, 40h, 20h, 10h, 08h, 04h, 02h, 01h
  80.  
  81.                 ; masks to select right bits in word indexed by offset
  82.  
  83. ltable  dw      0FFFFh, 07FFFh, 03FFFh, 01FFFh
  84.         dw      00FFFh, 007FFh, 003FFh, 001FFh
  85.         dw      000FFh, 0007Fh, 0003Fh, 0001Fh
  86.         dw      0000Fh, 00007h, 00003h, 00001h
  87.  
  88.                 ; masks to select left bits in word indexed by offset
  89.  
  90. rtable  dw      08000h, 0C000h, 0E000h, 0F000h
  91.         dw      0F800h, 0FC00h, 0FE00h, 0FF00h
  92.         dw      0FF80h, 0FFC0h, 0FFE0h, 0FFF0h
  93.         dw      0FFF8h, 0FFFCh, 0FFFEh, 0FFFFh
  94.  
  95.  
  96. ; local variables
  97.  
  98. color   dw      ?
  99. x1      dw      ?
  100. x2      dw      ?
  101. y1      dw      ?
  102. y2      dw      ?
  103. yoff    dw      ?
  104. ycount  dw      ?
  105. x1woff  dw      ?
  106. x2woff  dw      ?
  107.  
  108. ;-----------------------------------------------------------------------
  109.         assume  cs:$paint,ds:$paint
  110.         assume  es:quadscreen
  111.  
  112. locate  PROC    NEAR
  113. ;
  114. ; Return pixel color at point (X,Y).
  115. ;
  116. ; Input:
  117. ;       X in SI
  118. ;       Y in DI
  119. ;       ES points to screen RAM
  120. ;
  121. ; Output:
  122. ;       Pixel color (0-1) in AL
  123. ;
  124. ; Registers modified:
  125. ;       Only AX
  126. ;
  127.  
  128.         push    bx              ; save registers
  129.         push    si
  130.  
  131.         mov     ax,si           ; x
  132.         shr     si,1            ; x/2
  133.         shr     si,1            ; x/4
  134.         shr     si,1            ; (x/8) = byte number
  135.         and     ax,07h          ; bit offset in byte
  136.         mov     bx,di           ; y
  137.         shl     bx,1            ; y*2
  138.         shl     bx,1            ; y*4
  139.         shl     bx,1            ; y*8
  140.         shl     bx,1            ; y*16
  141.         shl     bx,1            ; y*32
  142.         shl     bx,1            ; y*64
  143.         shl     bx,1            ; y*128
  144.         mov     ah,es:[bx+si]   ; Get byte from y*128 + (x/8)
  145.         xor     bh,bh           ; clear top of bx
  146.         mov     bh,al           ; bit offset into bx
  147.         xor     al,al           ; al=0
  148.         and     ah,bmask[bx]    ; mask all but selected bit
  149.         jz      locate_done     ; return with al=0
  150.         mov     al,1            ; return with al=1
  151.  
  152. locate_done:
  153.         pop     si              ; restore registers
  154.         pop     bx
  155.         ret                     ; return to caller
  156.  
  157. locate  ENDP
  158.  
  159. ;-----------------------------------------------------------------------
  160.         assume  cs:$paint,ds:$paint
  161.         assume  es:quadscreen
  162.  
  163. fill_partial_box PROC   NEAR
  164. ;
  165. ; Common routine to fill partial word at same offset in scanline group
  166. ;
  167. ; Input:
  168. ;       ax - mask to select bits in word
  169. ;       bx - word offset of word containing starting x in scanline
  170. ;       di - fill color
  171. ;       es - video RAM segment
  172. ;       ycount - scan line count
  173. ;       yoff - starting scan line byte offset in video RAM
  174. ;
  175. ; Output:
  176. ;       Just to screen
  177. ;
  178. ; Registers modified:
  179. ;       ax,bx,cx,dx,bp,si
  180. ;
  181.         mov     bp,di           ; fill color
  182.         and     bp,ax           ; select bits x1..x2
  183.         not     ax              ; mask to exclude bits x1..x2
  184.         shl     bx,1            ; convert word offset to byte offset
  185.         mov     si,yoff         ; scanline offset in video RAM
  186.         add     si,bx           ; si <- yoff+bx for address of first word
  187.         mov     cx,ycount       ; outer loop count of scan lines
  188.         mov     bx,y_inc        ; scanline increment
  189.  
  190. fill_partial_1:
  191.         mov     dx,es:[si]      ; word from video RAM
  192.         and     dx,ax           ; clear selected bits
  193.         or      dx,bp           ; set selected bits
  194.         mov     es:[si],dx      ; store word back in video RAM
  195.         add     si,bx           ; point to next scan line
  196.         loop    fill_partial_1  ; decrement cx, loop while cx > 0
  197.  
  198.         ret                     ; return to caller
  199. fill_partial_box ENDP
  200.  
  201. ;-----------------------------------------------------------------------
  202.         assume  cs:$paint,ds:$paint
  203.         assume  es:quadscreen
  204.  
  205. setbox  PROC    NEAR
  206. ;
  207. ; Fill box with upper left corner  at (x1,y1) and lower right corner  at
  208. ; (x2,y2) with value 0..1 in color.
  209. ;
  210. ; Input:
  211. ;       Global variables x1,y1,x2,y2,color
  212. ;       ES points to screen RAM
  213. ;
  214. ; Output:
  215. ;       Just to screen
  216. ;
  217. ; Registers modified:
  218. ;       None
  219. ;
  220. ; Note:
  221. ;       Assumes (and exits immediately if not so)
  222. ;       0 <= x1 <= x2 <= 1023
  223. ;       0 <= y1 <= y2 <= 511
  224. ;
  225.         push    ax              ; save registers
  226.         push    bx
  227.         push    cx
  228.         push    dx
  229.         push    bp
  230.         push    di
  231.         push    si
  232.  
  233.         mov     di,0FFFFh       ; fill with ones
  234.         test    color,di        ; test color
  235.         jz      setbox_1        ; yes, ones
  236.         xor     di,di           ; fill with zeros
  237.  
  238. setbox_1:
  239.         mov     ax,x1
  240.         cmp     ax,x2           ; x2 >= x1?
  241.         jna     setbox_2        ; yes
  242.         jmp     setbox_done     ; no, exit immediately
  243.  
  244. setbox_2:
  245.         mov     cx,y2
  246.         inc     cx              ; y2 + 1
  247.         sub     cx,y1           ; scan line count = y2 + 1 - y1
  248.         test    cx,cx           ; count > 0?
  249.         jg      setbox_3        ; yes
  250.         jmp     setbox_done     ; no, exit immediately
  251.  
  252. setbox_3:
  253.         mov     ycount,cx       ; save scan line count
  254.         mov     si,y1           ; y1
  255.         shl     si,1            ; y1*2
  256.         shl     si,1            ; y1*4
  257.         shl     si,1            ; y1*8
  258.         shl     si,1            ; y1*16
  259.         shl     si,1            ; y1*32
  260.         shl     si,1            ; y1*64
  261.         shl     si,1            ; y1*128
  262.         mov     yoff,si         ; yoff = y1*128
  263.  
  264. ; The rectangle fill divides into two cases, (a) x1..x2 in one word, and
  265. ; (b) x1..x2 spanning more than one word.  In order to avoid unnecessary
  266. ; recomputation, the fill in case (b)  is split into three loops,  first
  267. ; the left partial word, then the  run of complete words, and last,  the
  268. ; right partial word.   This gives  three tight loops  with an  absolute
  269. ; minimum of computation and memory references restricted to the  single
  270. ; fetch and store of  the video RAM data,  with all other quantities  in
  271. ; registers.  If  the  left  and/or  right partial  words  are  in  fact
  272. ; complete words, their  corresponding loops are  skipped and the  count
  273. ; and start of the complete word loop are correspondingly adjusted so as
  274. ; to include them.
  275.  
  276.         mov     bx,x1
  277.         and     bx,0FFF0h       ; word offset for x1
  278.         mov     x1woff,bx       ; save word offset
  279.         mov     bp,x2
  280.         and     bp,0FFF0h       ; word offset for x2
  281.         mov     x2woff,bp       ; save word offset
  282.         cmp     bp,bx           ; x2 in same word as x1?
  283.         ja      setbox_4        ; no
  284.  
  285.         mov     bx,x1           ; yes, special case -- x1..x2 in one word
  286.         and     bx,0Fh          ; bit offset in word
  287.         mov     ax,rtable[bx]   ; mask to choose bits at right
  288.  
  289.         mov     bp,x2
  290.         and     bp,0Fh          ; bit offset in word
  291.         and     ax,ltable[bp]   ; combine masks to select bits x1..x2
  292.  
  293.         mov     bx,x1woff
  294.         call    fill_partial_box
  295.  
  296.         jmp     setbox_done     ; exit
  297. ;
  298. ; General case -- x1..x2 span one or more words, split into three loops
  299. ;
  300.  
  301. ;
  302. ; First loop - set bits in partial word left of scanline
  303. ;
  304. setbox_4:
  305.         mov     bp,x1
  306.         and     bp,0Fh          ; bit offset in word
  307.         jz      setbox_5        ; skip first loop if fullword
  308.         mov     ax,rtable[bp]   ; select mask for bits to right
  309.         mov     bx,x1woff       ; word offset
  310.         call    fill_partial_box
  311. ;
  312. ; Second loop - set complete words in scanlines
  313. ;
  314. setbox_5:
  315.         mov     bx,x1woff       ; word offset
  316.         mov     bp,x2woff       ; word offset
  317.         dec     bp
  318.         sub     bp,bx           ; tentative count of complete words to fill
  319.  
  320.         test    x1,0Fh          ; first word complete?
  321.         jnz     setbox_6        ; no
  322.         inc     bp              ; yes, include it in loop 2
  323.         jmp     short setbox_7
  324.  
  325. setbox_6:
  326.         inc     bx              ; partial word - adjust offset to 1st fullword
  327.  
  328. setbox_7:
  329.         mov     ax,x2
  330.         and     ax,0Fh          ; bit offset in last word
  331.         cmp     ax,0Fh          ; last word complete?
  332.         jne     setbox_8        ; no
  333.         inc     bp              ; yes, include it in loop 2
  334.  
  335. setbox_8:
  336.         test    bp,bp           ; count >= 0?
  337.         jna     setbox_10       ; skip loop if 2 adjacent partial words
  338.  
  339.         mov     ax,di           ; fill color
  340.         shl     bx,1            ; convert word offset to byte offset
  341.         mov     si,yoff         ; scanline offset in video RAM
  342.         add     si,bx           ; si <- yoff+bx for address of first word
  343.         mov     cx,ycount       ; outer loop count of scan lines
  344.         mov     bx,y_inc        ; scanline increment
  345.         cld                     ; clear direction flag for increment of di
  346.  
  347. ; Loop 2 -- run of full words
  348.  
  349. setbox_9:
  350.         mov     di,si           ; address of first full words
  351.         mov     dx,cx           ; save outer loop count
  352.         mov     cx,bp           ; inner loop count
  353.         rep stosw               ; loop filling ax into [es:di]
  354.         mov     cx,dx           ; restore output loop count
  355.         add     si,bx           ; point to next scan line
  356.         loop    setbox_9        ; decr cx, loop while cx > 0
  357.  
  358.         mov     di,ax           ; restore fill color
  359. ;
  360. ; Set bits in partial word right of scanline
  361. ;
  362. setbox_10:
  363.         mov     bp,x2
  364.         and     bp,0Fh          ; bit offset
  365.         cmp     bp,0Fh          ; fullword?
  366.         je      setbox_done     ; yes, already filled by loop 2
  367.         mov     ax,ltable[bp]   ; mask to select bits 0..x2
  368.         mov     bx,x2woff       ; word offset
  369.         call    fill_partial_box
  370.  
  371. setbox_done:                    ; restore registers
  372.         pop     si
  373.         pop     di
  374.         pop     bp
  375.         pop     dx
  376.         pop     cx
  377.         pop     bx
  378.         pop     ax
  379.         ret                     ; return to caller
  380.  
  381. setbox  ENDP
  382.  
  383. ;-----------------------------------------------------------------------
  384.         assume  cs:$paint,ds:$paint
  385.  
  386. pushpaint PROC  NEAR
  387.         dec     bp              ; bp is paint stack pointer
  388.         dec     bp              ; and gets decremented first
  389.         mov     [bp],si         ; push x
  390.         dec     bp
  391.         dec     bp
  392.         mov     [bp],di         ; push y
  393.         ret
  394. pushpaint ENDP
  395.  
  396. ;-----------------------------------------------------------------------
  397.         assume  cs:$paint,ds:$paint
  398.  
  399. poppaint PROC   NEAR
  400. ;
  401. ; poppaint pops x- and y-coordinates off paint stack
  402. ;
  403.         mov     di,[bp]         ; pop y
  404.         inc     bp              ; increment paint stack pointer
  405.         inc     bp
  406.         mov     di,[bp]         ; pop x
  407.         inc     bp              ; increment paint stack pointer
  408.         inc     bp
  409.         ret
  410. poppaint ENDP
  411.  
  412. ;-----------------------------------------------------------------------
  413.  
  414.  
  415. argcnt  equ     3
  416. x       equ     [bp]
  417. y       equ     [bp-2]
  418. colval  equ     [bp-4]
  419.                                 ; return address as CS:offset at [BP-6..9]
  420.                                 ; old BP at [BP-10..11]
  421. spbias  equ     10              ; new sp points at last local stack variable
  422.  
  423.  
  424.         assume  cs:$paint,ds:$paint
  425.  
  426. paint   PROC    FAR
  427.  
  428.         push    bp              ; Save caller's frame pointer
  429.         mov     bp,sp           ; and set up our own.
  430.         add     bp,4+2*argcnt   ; Point to top of arg list on stack
  431.         sub     sp,spbias       ; Reserve space for locals on stack
  432.  
  433.         push    ds
  434.         mov     ax,cs
  435.         mov     ds,ax           ; establish ds=cs addressability
  436.  
  437.         mov     si,x
  438.         mov     di,y
  439.         mov     ax,colval
  440.         mov     color,ax
  441.         mov     dx,color     ; initialize paint color
  442. ;
  443. ; bp no longer used as variable pointer
  444. ;
  445.         mov     ax,quadscreen
  446.         mov     es,ax           ; establish quadscreen addressability
  447. ;
  448. ; initialize paint stack
  449. ;
  450.         mov     bp,paintstack   ; bp is set to top of stack
  451.         call    pushpaint       ; push interior point onto stack
  452. ;
  453. ; main loop for painting
  454. ;
  455. paint1:
  456.         mov     ax,paintstack   ; stack empty?
  457.         cmp     bp,ax
  458.         jne     paint2          ; continue if not
  459.         jmp     endpaint        ; else exit
  460.  
  461. ;
  462. ; get the next place to paint
  463. ;
  464. paint2:
  465.         call    poppaint        ; pop the next place to paint
  466.         call    locate          ; color is returned in al
  467.         cmp     al,dl           ; is it filled?
  468.         je      paint1          ; yes
  469.         cmp     al,dh           ; is it boundary?
  470.         je      paint1          ; yes
  471.         cmp     di,scr_top      ; top of screen?
  472.         jl      paint1          ; no
  473.         cmp     di,scr_bot      ; bottom of screen?
  474.         jg      paint1          ; yes
  475. ;
  476. ; move right until boundary reached
  477. ;
  478. paint3:
  479.         inc     si              ; x <-- x + 1
  480.         call    locate          ; look right
  481.         dec     si              ; restore x
  482.  
  483.         cmp     al,dl           ; is it filled?
  484.         je      paint4          ; yes
  485.         cmp     al,dh           ; is it boundary?
  486.         je      paint4          ; yes
  487.         cmp     si,scr_right    ; at right screen boundary?
  488.         je      paint4          ; yes
  489.         inc     si              ; x <-- x + 1
  490.         jmp     paint3
  491. ;
  492. ; push above and below
  493. ;
  494. paint4:
  495.         dec     di              ; y <-- y - 1
  496.         call    locate          ; check above
  497.         mov     bh,al           ; save above state
  498.         cmp     al,dl           ; is it filled?
  499.         je      paint5          ; yes
  500.         cmp     al,dh           ; is it boundary color?
  501.         je      paint5          ; yes
  502.         call    pushpaint       ; no, push above
  503.  
  504. paint5:
  505.         inc     di              ; restore y
  506.         inc     di              ; y <-- y + 1
  507.         call    locate          ; check below
  508.         mov     bl,al           ; save below state
  509.         cmp     al,dl           ; is it filled?
  510.         je      paint6          ; yes
  511.         cmp     al,dh           ; is it boundary color
  512.         je      paint6
  513.         call    pushpaint       ; push below
  514.  
  515. paint6:
  516.         dec     di              ; restore y
  517. ;
  518. ; anchor the end point of the scan line
  519. ;
  520.         mov     x2,si           ; store x-coordinate of end of scan line
  521.         mov     y2,di           ; store y-coordinate of end of scan line
  522. ;
  523. ; plot as we scan left, checking above and below
  524. ;
  525. paint7:
  526.         dec     di              ; y <-- y - 1
  527.         call    locate          ; check above
  528.         cmp     al,dl           ; is it filled?
  529.         je      paint9
  530.         cmp     al,dh           ; is it boundary color?
  531.         je      paint9
  532.  
  533.         cmp     bh,dl           ; last above filled?
  534.         je      paint8          ; yes
  535.         cmp     bh,dh           ; boundary color?
  536.         jne     paint9          ; no
  537.  
  538. paint8:
  539.         call    pushpaint       ; push above if new place to paint
  540.  
  541. paint9:
  542.         mov     bh,al           ; update last above
  543.         inc     di              ; restore y
  544.         inc     di              ; y <-- y + 1
  545.         call    locate          ; check below
  546.         cmp     al,dl           ; is it filled?
  547.         je      paint11         ; yes
  548.         cmp     al,dh           ; is it boundary color?
  549.         je      paint11         ; yes
  550.  
  551.         cmp     bl,dl           ; last below filled?
  552.         je      paint10         ; yes
  553.         cmp     bl,dh           ; was it boundary color?
  554.         jne     paint11         ; no
  555.  
  556. paint10:
  557.         call    pushpaint       ; push below if new place to paint
  558. paint11:
  559.         dec     di              ; restore y
  560.         mov     bl,al           ; update last below
  561.  
  562.         dec     si              ; move left, x <-- x - 1
  563.         jl      paint12         ; stop the scan if too far left
  564.         call    locate          ; check the point
  565.         cmp     al,dl           ; hit filled yet?
  566.         je      paint12         ; yes, next scan line
  567.         cmp     al,dh           ; hit boundary yet?
  568.         jne     paint7          ; no
  569.  
  570. paint12:                        ; yes, continue next scan line
  571.         inc     si              ; restore x
  572.         mov     x1,si           ; store x-coordinate of start
  573.         mov     y1,di           ; store y-coordinate of start
  574.         call    setbox          ; plot the scan line
  575.         jmp     paint1          ; next place to paint
  576.  
  577. endpaint:
  578.         pop     ds              ; restore ds
  579.         add     sp,spbias       ; restore original sp at entry
  580.         pop     bp              ; and callers frame pointer
  581.         ret     2*argcnt        ; and return discarding stack arguments
  582.  
  583. paint   ENDP
  584.  
  585. ;-----------------------------------------------------------------------
  586.  
  587. $paint  ENDS
  588.         END
  589.